/**
 ******************************************************************************
 * @file           : bsp_can.c
 * @brief          : CAN Driver Implementation (STM32F4xx)
 ******************************************************************************
 * @attention
 *
 * CAN驱动实现文件
 * 使用GPIO AF复用功能
 *
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "./BSP/CAN/bsp_can.h"
#include "./BSP/CAN/bsp_can_config.h"

/* Private includes ----------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
static CAN_HandleTypeDef sg_can_handle;
static can_rx_callback_t sg_rx_callback = NULL;

/* Private function prototypes -----------------------------------------------*/
static void can_gpio_init(void);
static void can_calculate_baudrate(uint32_t baudrate, uint32_t *prescaler, uint32_t *bs1, uint32_t *bs2);

/* Private functions ---------------------------------------------------------*/

/**
 * @brief       CAN GPIO初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        STM32F4xx使用GPIO AF复用功能
 */
static void can_gpio_init(void)
{
    GPIO_InitTypeDef gpio_init_struct = {0};

    /* 使能GPIO时钟 */
    CAN_TX_GPIO_CLK_ENABLE();
    CAN_RX_GPIO_CLK_ENABLE();

    /* 配置TX引脚（复用推挽输出） */
    gpio_init_struct.Pin = CAN_TX_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_AF_PP;
    gpio_init_struct.Pull = GPIO_PULLUP;
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    gpio_init_struct.Alternate = CAN_GPIO_AF;
    HAL_GPIO_Init(CAN_TX_GPIO_PORT, &gpio_init_struct);

    /* 配置RX引脚（复用推挽输入） */
    gpio_init_struct.Pin = CAN_RX_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_AF_PP;
    gpio_init_struct.Pull = GPIO_PULLUP;
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    gpio_init_struct.Alternate = CAN_GPIO_AF;
    HAL_GPIO_Init(CAN_RX_GPIO_PORT, &gpio_init_struct);
}

/**
 * @brief       计算CAN波特率参数
 *
 * @param[in]   baudrate 目标波特率
 * @param[out]  prescaler 预分频器
 * @param[out]  bs1 时间段1
 * @param[out]  bs2 时间段2
 *
 * @retval      无
 *
 * @note        CAN时钟42MHz（APB1）
 */
static void can_calculate_baudrate(uint32_t baudrate, uint32_t *prescaler, uint32_t *bs1, uint32_t *bs2)
{
    uint32_t can_clock = 42000000;  /* APB1时钟42MHz */

    /* 根据波特率选择最优配置 */
    switch (baudrate)
    {
        case 125000:
            *prescaler = 24;
            *bs1 = CAN_BS1_10TQ;
            *bs2 = CAN_BS2_3TQ;
            break;
        case 250000:
            *prescaler = 12;
            *bs1 = CAN_BS1_10TQ;
            *bs2 = CAN_BS2_3TQ;
            break;
        case 500000:
            *prescaler = 6;
            *bs1 = CAN_BS1_10TQ;
            *bs2 = CAN_BS2_3TQ;
            break;
        case 1000000:
            *prescaler = 3;
            *bs1 = CAN_BS1_10TQ;
            *bs2 = CAN_BS2_3TQ;
            break;
        default:
            /* 默认500kbps */
            *prescaler = 6;
            *bs1 = CAN_BS1_10TQ;
            *bs2 = CAN_BS2_3TQ;
            log_w("Unsupported baudrate %u, using 500kbps", baudrate);
            break;
    }
}

/* Exported functions --------------------------------------------------------*/

/**
 * @brief       CAN初始化
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        配置CAN波特率和过滤器
 */
void can_init(void)
{
    uint32_t prescaler, bs1, bs2;

    /* 使能CAN时钟 */
    CAN_CANx_CLK_ENABLE();

    /* 初始化GPIO */
    can_gpio_init();

    /* 计算波特率参数 */
    can_calculate_baudrate(CAN_BAUDRATE, &prescaler, &bs1, &bs2);

    /* 配置CAN */
    sg_can_handle.Instance = CAN_CANx;
    sg_can_handle.Init.Prescaler = prescaler;
    sg_can_handle.Init.Mode = CAN_MODE_CONFIG;
    sg_can_handle.Init.SyncJumpWidth = CAN_SJW_1TQ;
    sg_can_handle.Init.TimeSeg1 = bs1;
    sg_can_handle.Init.TimeSeg2 = bs2;
    sg_can_handle.Init.TimeTriggeredMode = DISABLE;
    sg_can_handle.Init.AutoBusOff = ENABLE;
    sg_can_handle.Init.AutoWakeUp = DISABLE;
    sg_can_handle.Init.AutoRetransmission = ENABLE;
    sg_can_handle.Init.ReceiveFifoLocked = DISABLE;
    sg_can_handle.Init.TransmitFifoPriority = DISABLE;

    if (HAL_CAN_Init(&sg_can_handle) != HAL_OK)
    {
        log_e("CAN initialization failed");
        return;
    }

    /* 配置默认过滤器（接收所有） */
    can_filter_config(0x00, 0x00);

    /* 配置中断优先级并使能 */
    HAL_NVIC_SetPriority(CAN_CANx_RX_IRQn, 2, 0);
    HAL_NVIC_EnableIRQ(CAN_CANx_RX_IRQn);

    /* 启动CAN */
    if (HAL_CAN_Start(&sg_can_handle) != HAL_OK)
    {
        log_e("CAN start failed");
        return;
    }

    /* 使能接收中断 */
    if (HAL_CAN_ActivateNotification(&sg_can_handle, CAN_IT_RX_CONFIG) != HAL_OK)
    {
        log_e("CAN RX interrupt enable failed");
        return;
    }

    log_i("CAN%d initialized: %u bps, Mode=%d", CAN_SELECT_NUM, CAN_BAUDRATE, CAN_MODE);
}

/**
 * @brief       CAN去初始化
 *
 * @param       无
 *
 * @retval      无
 */
void can_deinit(void)
{
    /* 停止CAN */
    HAL_CAN_Stop(&sg_can_handle);

    /* 禁用中断 */
    HAL_NVIC_DisableIRQ(CAN_CANx_RX_IRQn);

    /* 去初始化CAN */
    HAL_CAN_DeInit(&sg_can_handle);

    log_i("CAN%d deinitialized", CAN_SELECT_NUM);
}

/**
 * @brief       配置CAN过滤器
 *
 * @param[in]   id 要接收的CAN ID
 * @param[in]   mask 掩码（0=不关心，1=必须匹配）
 *
 * @retval      无
 *
 * @note        mask=0x00接收所有，mask=0x7FF精确匹配标准帧
 */
void can_filter_config(uint32_t id, uint32_t mask)
{
    CAN_FilterTypeDef filter_config;

    filter_config.FilterBank = 0;
    filter_config.FilterMode = CAN_FILTERMODE_IDMASK;
    filter_config.FilterScale = CAN_FILTERSCALE_32BIT;
    filter_config.FilterIdHigh = (id << 5) >> 16;
    filter_config.FilterIdLow = (id << 5) & 0xFFFF;
    filter_config.FilterMaskIdHigh = (mask << 5) >> 16;
    filter_config.FilterMaskIdLow = (mask << 5) & 0xFFFF;
    filter_config.FilterFIFOAssignment = CAN_RX_FIFO_CONFIG;
    filter_config.FilterActivation = ENABLE;

#if (CAN_SELECT_NUM == 2)
    filter_config.SlaveStartFilterBank = 14;
#endif

    if (HAL_CAN_ConfigFilter(&sg_can_handle, &filter_config) != HAL_OK)
    {
        log_e("CAN filter configuration failed");
    }
}

/**
 * @brief       发送CAN消息
 *
 * @param[in]   msg CAN消息结构体
 *
 * @retval      0=成功，1=失败
 */
uint8_t can_send(const CAN_Message_t *msg)
{
    CAN_TxHeaderTypeDef tx_header;
    uint32_t tx_mailbox;

    if (msg == NULL || msg->dlc > 8)
    {
        return 1;
    }

    /* 配置发送头 */
    if (msg->ide == 0)
    {
        tx_header.StdId = msg->id;
        tx_header.IDE = CAN_ID_STD;
    }
    else
    {
        tx_header.ExtId = msg->id;
        tx_header.IDE = CAN_ID_EXT;
    }

    tx_header.RTR = msg->rtr ? CAN_RTR_REMOTE : CAN_RTR_DATA;
    tx_header.DLC = msg->dlc;
    tx_header.TransmitGlobalTime = DISABLE;

    /* 发送数据 */
    if (HAL_CAN_AddTxMessage(&sg_can_handle, &tx_header, (uint8_t *)msg->data, &tx_mailbox) != HAL_OK)
    {
        log_e("CAN send failed");
        return 1;
    }

    return 0;
}

/**
 * @brief       发送标准帧
 *
 * @param[in]   id CAN ID（11位）
 * @param[in]   data 数据缓冲区
 * @param[in]   len 数据长度（0-8）
 *
 * @retval      0=成功，1=失败
 */
uint8_t can_send_std(uint32_t id, const uint8_t *data, uint8_t len)
{
    CAN_Message_t msg;

    if (id > 0x7FF || len > 8 || data == NULL)
    {
        return 1;
    }

    msg.id = id;
    msg.ide = 0;  /* 标准帧 */
    msg.rtr = 0;  /* 数据帧 */
    msg.dlc = len;

    for (uint8_t i = 0; i < len; i++)
    {
        msg.data[i] = data[i];
    }

    return can_send(&msg);
}

/**
 * @brief       发送扩展帧
 *
 * @param[in]   id CAN ID（29位）
 * @param[in]   data 数据缓冲区
 * @param[in]   len 数据长度（0-8）
 *
 * @retval      0=成功，1=失败
 */
uint8_t can_send_ext(uint32_t id, const uint8_t *data, uint8_t len)
{
    CAN_Message_t msg;

    if (id > 0x1FFFFFFF || len > 8 || data == NULL)
    {
        return 1;
    }

    msg.id = id;
    msg.ide = 1;  /* 扩展帧 */
    msg.rtr = 0;  /* 数据帧 */
    msg.dlc = len;

    for (uint8_t i = 0; i < len; i++)
    {
        msg.data[i] = data[i];
    }

    return can_send(&msg);
}

/**
 * @brief       接收CAN消息
 *
 * @param[out]  msg CAN消息结构体
 *
 * @retval      0=成功，1=失败
 */
uint8_t can_receive(CAN_Message_t *msg)
{
    CAN_RxHeaderTypeDef rx_header;

    if (msg == NULL)
    {
        return 1;
    }

    /* 检查FIFO是否有数据 */
    if (HAL_CAN_GetRxFifoFillLevel(&sg_can_handle, CAN_RX_FIFO_CONFIG) == 0)
    {
        return 1;  /* FIFO空 */
    }

    /* 读取消息 */
    if (HAL_CAN_GetRxMessage(&sg_can_handle, CAN_RX_FIFO_CONFIG, &rx_header, msg->data) != HAL_OK)
    {
        return 1;
    }

    /* 填充消息结构体 */
    if (rx_header.IDE == CAN_ID_STD)
    {
        msg->id = rx_header.StdId;
        msg->ide = 0;
    }
    else
    {
        msg->id = rx_header.ExtId;
        msg->ide = 1;
    }

    msg->rtr = (rx_header.RTR == CAN_RTR_REMOTE) ? 1 : 0;
    msg->dlc = rx_header.DLC;

    return 0;
}

/**
 * @brief       设置接收回调函数
 *
 * @param[in]   callback 回调函数指针
 *
 * @retval      无
 */
void can_set_rx_callback(can_rx_callback_t callback)
{
    sg_rx_callback = callback;
}

/**
 * @brief       CAN FIFO0 接收中断回调
 *
 * @param[in]   hcan CAN句查
 *
 * @retval      无
 */
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
    CAN_Message_t msg;

    if (hcan->Instance == CAN_CANx)
    {
        if (can_receive(&msg) == 0 && sg_rx_callback != NULL)
        {
            sg_rx_callback(&msg);
        }
    }
}

/**
 * @brief       CAN FIFO1 接收中断回调
 *
 * @param[in]   hcan CAN句查
 *
 * @retval      无
 */
void HAL_CAN_RxFifo1MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
    CAN_Message_t msg;

    if (hcan->Instance == CAN_CANx)
    {
        if (can_receive(&msg) == 0 && sg_rx_callback != NULL)
        {
            sg_rx_callback(&msg);
        }
    }
}

/**
 * @brief       CAN接收中断服务函数
 *
 * @param       无
 *
 * @retval      无
 *
 * @note        在stm32f4xx_it.c中调用此函数
 */
void CAN_CANx_RX_IRQHandler(void)
{
    HAL_CAN_IRQHandler(&sg_can_handle);
}
